Restful一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制:

CORS CORS是现代浏览亲支持快于请求的一种方式,全称是“跨域资源共享“(Cross-origin resource sharing),当使用XMLHttpRequest发送请求时,浏览器发现该请求不符合同源测率,会给该请求头:Origin,后台进行以系列处理,如果确定请求则在返回结果加入一个响应头:Access-Control-Allow-Origin;浏览器判断该响应头中是否包含Origin的值,如果有浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器之间驳回,这时我们无法拿到响应数据

JWT :Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密;

FastDFS :FastDFS 是用 c 语言编写的一款开源的分布式文件系统。FastDFS 为互联网量身定制, 充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用 FastDFS 很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。FastDFS 架构包括 Tracker server 和 Storage server。客户端请求 Tracker server 进行文 件上传、下载,通过 Tracker server 调度最终由 Storage server 完成文件上传和下载。


Web网站中开发模式(前后端分离&前后端不分离)

web开发模式

开发模式 说明
前后端不分离 前端展示的数据效果最终是由后端进行控制的,由后端使用模板进行模板的渲染,将渲染后的内容返回给客户端进行显示
前后端分离 后端服务器只返回前端所需要数据,前端获取数据之后自己控制数据怎么进行展示

注意:前端发起ajax->后端服务器返回分类新闻数据->前端进行页面拼接和展示。

RestAPI接口风格

前后端分离开发中广泛采用的一种API设计风格。
​关键点:
url地址尽量使用名词,不要出现动词
采用不同请求方式,执行不同操作

GET 获取
​POST 新增
PUT 修改
​DELETE 删除
GET /books/: 获取所有图书,返回所有图书信息
POST /books/: 新建一本图书,返回新建的图书信息
GET /books/id/: 获取指定图书,返回指定图书信息
PUT /books/id/: 修改指定图书,返回修改图书信息
DELETE /books/id/: 删除指定图书,返回空文档

过滤参数放在查询字符串中
响应状态码选择

200:获取或修改
​201:新建
​204:删除
​400:客户端请求有误
​404:客户端请求的资源找不到
​500:服务器出错

响应数据返回json

使用Django知识自定义RestAPI接口

准备工作->创建应用->定义模板类->生成数据表->添加测试数据。

使用Django知识自定义RestAPI接口:

  1. 获取所有图书的信息 GET /books/
  2. 新增一本图书信息 POST /books/
  3. 获取指定的图书信息 GET /books/(?P\d+)/
  4. 修改指定的图书信息 PUT /books/(?P\d+)/
  5. 删除指定的图书信息 DELETE /books/(?P\d+)/

RestAPI接口开发时的工作(序列化和反序列化)

开发模式 说明
序列化 将程序中一种数据结构类型转化为其他的数据格式,这个过程叫做序列化。在我们前面例子中,将模型对象转化为python字典或json数据,这个过程可以认为是序列化过程。
反序列化: 将其他格式数据转换为程序中数据,这个过程叫做反序列化。在我们前面例子中,将客户端发送的数据保存在模型对象中,这个过程可以认为是反序列化过程。

主要工作

​ 1)将请求数据保存在模型对象中(反序列化)。
​ 2)操作数据库。
​ 3)将模型对象转换为前端所需的格式(序列化)。

##

序列化器|视图类|拓展类

序列化类的功能:进行序列化和反序列化

序列化:将对象转化为字典数据
反序列化:1)数据校验
2)数据保存(新增&更新)。
定义序列化器类:
继承Serializer或ModelSerializer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from rest_framework import serializers

# serializers.Serializer:定义任何序列化器类时,都可以直接继承于Serializer
# serializers.ModelSerializer:如果定义的序列化器类针对的是一个模型类,可以直接继承ModelSerializer

class User(object):
def __init__(self, username, age):
self.username = username
self.age = age

class UserSerializer(serializers.Serializer):
"""序列化器类"""
# 序列化器字段 = serializers.字段类型(选项参数)
username = serializers.CharField()
age = serializers.IntegerField()


if __name__ == '__main__':
user = User('smart', 18)
# {
# "username": "smart",
# "age": 18
# }

serializer = UserSerializer(user)
# 获取序列化之后的字典数据
serializer.data

"hello"

1. 序列化器-序列化

1)序列化单个对象

1
2
3
book = BookInfo.objects.get(id=1)
serializer = BookInfoSerializer(book)
serializer.data

2)序列化多个对象

1
2
3
books = BookInfo.objects.all()
serializer = BookInfoSerializer(books, many=True)
serializer.data

3)关联对象的序列化

1
2
3
4
5
1. 将关联对象序列化为关联对象主键 PrimaryKeyRelatedFieldå
2. 将关联对象使用指定的序列化器进行序列化
3. 将关联对象序列化为关联对象模型类__str__方法的返回值 StringRelatedField

注意:如果关联对象有多个,定义字段时,需要添加many=True

2. 序列化器-反序列化

1)反序列化之数据校验

1
2
3
4
5
6
7
8
9
10
11
data = {'btitle': 'python'}

serializer = BookInfoSerializer(data=data)
serializer.is_valid() # 调用此方法会对传递的data数据内容进行校验,校验成功返回True, 否则返回False
serializer.errors # 获取校验失败的错误信息
serializer.validated_data # 获取校验之后的数据

# 补充验证行为
1. 对对应的字段指定validators
2. 序列化器类中定义对应的方法validate_<field_name>对指定的字段进行校验
3. 如果校验需要结合多个字段内容,定义validate方法

2)反序列化之数据保存(新增或更新)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 数据校验之后,调用此方法可以进行数据保存,可能会调用序列化器类中的create或update
serializer.save()

# 调用create,创建序列化器对象时只传递了data
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()
serializer.save()

# 调用update,创建序列化器对象时传递了data和对象
book = BookInfo.objects.get(id=1)
data = {'btitle': 'python'}
serializer = BookInfoSerializer(book, data=data)
serializer.is_valid()
serializer.save()

# 注意: Serializer类中create和update没有进行实现,需要自己实现代码。

3. 使用Serializer改写Django自定义RestAPI接口

将序列化和反序列化部分代码使用序列化器完成。

4. APIView视图类&Request对象&Response对象

1)APIView视图类

​ APIView是DRF框架中所有视图类的父类。

​ 继承自APIView之后,处理函数中的request参数不再是Django原始的HttpRequest对象,而是由DRF框架封装的Request类的对象。

​ 进行异常处理。

​ 认证&权限&限流。

2)Request类
| 属性 | 说明 |
| :——– | ——–:|
| equest.data: | 包含传递的请求体数据(比如之前的request.body和request.POST),并且已经转换成了字典或类字典类型。 |
| 前后端分离 | 包含查询字符串参数(相当于之前的request.GET) |

3)Response类

​ 通过Response返回响应数据时,会根据前端请求头中的Accept转化成对应的响应数据类型,仅支持json和html,默认返回json。

4)补充

类视图对象`self.kwargs`保存这从url地址中提取的所有命名参数。

5. 使用APIView改写Django自定义RestAPI接口

将获取参数以及响应部分代码进行改写。

6. GenericAPIView视图类

APIView类的子类,封装了操作序列化器和操作数据库的方法,经常和Mixin扩展类配合使用。

过滤&分页。

属性:

​serializer_class: 指定视图使用的序列化器类
​queryset: 指定视图使用的查询集

方法:

get_serializer_class: 返回当前视图使用的序列化器类
​get_serializer: 创建一个序列化器类的对象
​get_queryset: 获取当前视图使用的查询集
​get_object: 获取单个对象,默认根据主键进行查询

##子类视图类|视图集|路由Router
| 类名 | 说明 |
| ————– | ———————————————————— |
| APIView | 1)继承自View,封装了Django 本身的HttpRequest对象为Request对象。2)统一的异常处理。 3)认证&权限&限流。 |
| GenericAPIView | 1)继承自APIView,提供了操作序列化器和数据库数据的方法,通常和Mixin扩展类配合使用。2)过滤&分页。 |

1. Mixin扩展类

DRF提供了5个扩展类,封装了5个通用的操作流程。

类名 说明
ListModelMixin 提供了一个list方法,封装了返回模型数据列表信息的通用流程。
CreateModelMixin 提供了一个create方法,封装了创建一个模型对象数据信息的通用流程。
RetrieveModelMixin 提供了一个retrieve方法,封装了获取一个模型对象数据信息的通用流程。
UpdateModelMixin 提供了一个update方法,封装了更新一个模型对象数据信息的通用流程。
DestroyModelMixin 提供了一个destroy方法,封装了删除一个模型对象数据信息的通用流程。

2. 子类视图

为了方便我们开发RestAPI,DRF框架除了提供APIView和GenericAPIView视图类之外,还提供了一些子类视图类,这些子类视图类同时继承了GenericAPIView和对应的Mixin扩展类,并且提供了对应的请求方法。

类名 说明
ListAPIView 1)继承自ListModelMixin和GenericAPIView。2)如果想定义一个视图只提供列出模型列表信息的接口,继承此视图类是最快的方式。
CreateAPIView 1)继承自CreateModelMixin和GenericAPIView。2)如果想定义一个视图只提供创建一个模型信息的接口,继承此视图类是最快的方式。
RetrieveAPIView 1)继承自RetrieveModelMixin和GenericAPIView。2)如果想定义一个视图只提供获取一个模型信息的接口,继承此视图类是最快的方式。
UpdateAPIView 1)继承自UpdateModelMixin和GenericAPIView。2)如果只想定义一个视图只提供更新一个模型信息的接口,继承此视图类是最快的方式。
DestroyAPIView 1)继承自DestroyModelMixin和GenericAPIView。2)如果只想定义一个视图只提供删除一个模型信息的接口,继承此视图类是最快的方式。
ListCreateAPIView 1)继承自ListModelMixin,CreateModelMixin和GenericAPIView。2)如果只想定义一个视图提供列出模型列表创建一个模型信息的接口,继承此视图类是最快的方式。
RetrieveUpdateAPIView 1)继承自RetrieveModelMixin,UpdateModelMixin和GenericAPIView。2)如果只想定义一个视图提供获取一个模型信息更新一个模型信息的接口,继承此视图类是最快的方式。
RetrieveDestroyAPIView 1)继承自RetrieveModelMixin,DestroyModelMixin和GenericAPIView。2)如果只想定义一个视图提供获取一个模型信息删除一个模型信息的接口,继承此视图类是最快的方式。
RetrieveUpdateDestoryAPIView 1)继承自RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin和GenericAPIView。2)如果只想定义一个视图提供获取一个模型信息更新一个模型信息删除一个模型信息的接口,继承此视图类是最快的方式。

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 需求1:写一个视图,提供一个接口
1. 获取一组图书数据 GET /books/
class BookListView(ListAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer

# 需求2:写一个视图,提供一个接口
1. 获取指定的图书数据 GET /books/(?P<pk>\d+)/
class BookDetailView(RetrieveAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer

# 需求3:写一个视图,提供两个接口
1. 获取指定的图书数据 GET /books/(?P<pk>\d+)/
2. 更新指定的图书数据 PUT /books/(?P<pk>\d+)/
class BookDetailView(RetrieveUpdateAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer

3. 视图集类

将操作同一资源的处理方法放在同一个类中(视图集),处理方法不要以请求方式命名,而是以对应的action命名,

​ list: 提供一组数据

​ create: 创建一条新数据

​ retrieve: 获取指定的数据

​ update: 更新指定的数据

​ destroy: 删除指定的数据

进行url配置时需要指明请求方法和处理函数之间的对应关系。

类名 说明
ViewSet 1)继承自ViewSetMixin和APIView。2)如果使用视图集时不涉及数据库和序列化器的操作,可以直接继承此类。
GenericViewSet 1)继承自ViewSetMixin和GenericAPIView。2)如果使用视图集涉及数据库和序列化器的操作,可以直接继承此类。
ModelViewSet 1)继承自5个Mixin扩展类和GenericViewSet。2)如果使用视图集想一次提供通用的5种操作,继承这个类是最快的。
ReadOnlyModelViewSet 1)继承自ListModelMixin,RetrieveModelMixin和GenericViewSet。2)如果使用视图集想一次提供list操作和retrieve操作,继承这个类是最快的。

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 需求1:写一个视图集,提供以下两种操作
1. 获取一组图书信息(list) GET /books/
2. 新建一本图书信息(create) POST /books/
class BookInfoViewSet(ListModelMixin, CreateModelMixin, GenericViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer

# 需求2:写一个视图集,提供以下两种操作
1. 获取一组图书信息(list) GET /books/
2. 获取指定图书信息(retrieve) GET /books/(?P<pk>\d+)/
class BookInfoViewSet(ReadOnlyModelViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer

# 需求3:写一个视图集,提供以下三种操作
1. 获取一组图书信息(list) GET /books/
2. 获取指定图书信息(retrieve) GET /books/(?P<pk>\d+)/
3. 更新指定图书信息(update) PUT /books/(?P<pk>\d+)/
class BookInfoViewSet(UpdateModelMixin, ReadOnlyModelViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer

注: 除了常见的5种基本操作之外,如果想给一个视图集中添加其他处理方法,直接在视图集中定义即可。

4. 路由Router

1)路由Router是专门配合视图集来使用的,可以使用Router自动生成视图集中相应处理函数对应的URL配置项。

2)使用Router自动生成视图集中相应处理函数对应的URL配置项时,除了常见的5种基本操作之外,如果视图集中有添加的其他处理方法,则需要给这些方法加上action装饰器之后,才会动态生成其对应的URL配置项。

其他功能

1)认证&权限

2)限流

控制用户访问API接口的频率。

针对匿名用户和认证用户分别进行限流。

1
2
3
4
5
6
7
8
9
10
11
# 限流(针对匿名用户和认证用户分别进行限流控制)
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle', # 针对匿名用户
'rest_framework.throttling.UserRateThrottle' # 针对认证用户
),

# 限流频次设置
'DEFAULT_THROTTLE_RATES': {
'user': '5/minute', # 认证用户5次每分钟
'anon': '3/minute', # 匿名用户3次每分钟
},

针对匿名用户和认证用户统一进行限流。

1
2
3
4
5
6
7
8
9
# 限流(针对匿名用户和认证用户进行统一限流控制)
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.ScopedRateThrottle',
),

'DEFAULT_THROTTLE_RATES': {
'contacts': '5/minute',
'upload': '3/minute',
},

3)过滤&排序

4)分页

两种分页方式PageNumberPaginationLimitOffsetPagination

使用PageNumberPagination分页时,获取分页数据时可以通过page传递页码参数。如果想要分页时指定页容量,需要自定义分页类。

1
2
3
4
5
6
7
class StandardResultPagination(PageNumberPagination):
# 默认页容量
page_size = 3
# 指定页容量参数名称
page_size_query_param = 'page_size'
# 最大页容量
max_page_size = 5

使用LimitOffsetPagination分页时,获取分页数据时可以传递参数offset(偏移量)和limit(限制条数)。

注:如果使用的全局分页设置,某个列表视图如果不需要分页,直接在视图类中设置pagination_class = None

5)异常

DRF自带异常处理功能,可以对某些特定的异常进行处理并返回给客户端组织好的错误信息。能够处理的异常如下:

1
2
3
4
5
6
7
8
9
10
APIException 所有异常的父类
ParseError 解析错误
AuthenticationFailed 认证失败
NotAuthenticated 尚未认证
PermissionDenied 权限决绝
NotFound 未找到
MethodNotAllowed 请求方式不支持
NotAcceptable 要获取的数据格式不支持
Throttled 超过限流次数
ValidationError 校验失败

可以自定义DRF框架的异常处理函数(补充一些异常处理)并指定EXCEPTION_HANDLER配置项。

6)接口文档

× 请我吃糖~
打赏二维码